package cn.da.shuai.cool.gateway.filter;

import cn.da.shuai.cool.common.entity.R;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Slf4j
@Component
public class ResponseWrapperFilter implements GlobalFilter, Ordered {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();

        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        DataBufferUtils.release(join);

                        String responseBody = new String(content, StandardCharsets.UTF_8);

                        // 处理响应体
                        String result = processResponseBody(exchange, responseBody);

                        byte[] uppedContent = result.getBytes(StandardCharsets.UTF_8);
                        originalResponse.getHeaders().setContentLength(uppedContent.length);
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                return super.writeWith(body);
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };

        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    private String processResponseBody(ServerWebExchange exchange, String originalBody) {
        try {
            HttpStatusCode statusCode = exchange.getResponse().getStatusCode();
            HttpHeaders headers = exchange.getResponse().getHeaders();

            // 如果是错误状态码
            if (statusCode != null && statusCode.isError()) {

                if (headers.getContentType() == null || !headers.getContentType().toString().contains(MediaType.APPLICATION_JSON_VALUE)) {
                    headers.setContentType(MediaType.APPLICATION_JSON);
                }

                if (isJson(originalBody)) {
                    return originalBody;
                }
                return toJsonString(R.error(statusCode.value(), originalBody));
            }

            // 空响应体处理
            if (originalBody == null || originalBody.trim().isEmpty()) {
                return toJsonString(R.ok());
            }

            // 检查是否为JSON格式
            if (isJson(originalBody) && hasCodeField(originalBody)) {
                // 如果是JSON，检查是否包含code字段
                return originalBody;
            } else {
                // 非JSON格式，封装成统一格式
                return toJsonString(R.ok(originalBody));
            }

        } catch (Exception e) {
            // 处理过程中的任何异常
            return toJsonString(R.error("Response processing failed"));
        }
    }

    private boolean isJson(String str) {
        try {
            objectMapper.readTree(str);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private boolean hasCodeField(String jsonStr) {
        try {
            JsonNode jsonNode = objectMapper.readTree(jsonStr);
            return jsonNode.has("code");
        } catch (Exception e) {
            return false;
        }
    }

    private Object parseJson(String jsonStr) {
        try {
            return objectMapper.readValue(jsonStr, Object.class);
        } catch (Exception e) {
            return jsonStr;
        }
    }

    private String toJsonString(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            return toJsonString(R.error("JSON serialization failed"));
        }
    }


    @Override
    public int getOrder() {
        return -2; // 高优先级
    }
}